/*
* Copyright (C) 2003 Twink, spm7@waikato.ac.nz
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
* Current version 2008-2011 (c)IRainman a.rainman@gmail.com
* Last update 2010.11.16, fully compatible with StrongDC++
*/

#include "stdinc.h"

#include "WebServerManager.h"
#include "ShareManager.h"
#include "QueueManager.h"
#include "FinishedManager.h"
#include "LogManager.h"
#include "UploadManager.h"
#include "StringTokenizer.h"
#include "ResourceManager.h"
#include "SearchResult.h"

const static string NotFoundHeader = "HTTP/1.0 404 Not Found\r\n";

WebServerManager* Singleton<WebServerManager>::instance = NULL;

WebServerManager::WebServerManager(void) : started(false), page404(NULL), sended_search(false)/*, search_started(false) TODO */
{
	SettingsManager::getInstance()->addListener(this);
}

WebServerManager::~WebServerManager(void)
{
	SettingsManager::getInstance()->removeListener(this);
	if (started) Stop();
}

void WebServerManager::Start()
{
	try
	{
		if (started) return;
		Lock l(cs);
		if (started) return;
		started = true;
		
		socket.listen(static_cast<uint16_t>SETTING(WEBSERVER_PORT), SETTING(WEBSERVER_BIND_ADDRESS));
		socket.addListener(this);
		fire(WebServerListener::Setup());
		
		page404 = new WebPageInfo(PAGE_404, STRING(WEBSERVER_PAGE_NOT_FOUND));
		pages["/"] = new WebPageInfo(INDEX, "");
		pages["/index.htm"] = new WebPageInfo(INDEX, "");
		pages["/dlqueue.htm"] = new WebPageInfo(DOWNLOAD_QUEUE, STRING(DOWNLOAD_QUEUE));
		pages["/dlfinished.htm"] = new WebPageInfo(DOWNLOAD_FINISHED, STRING(FINISHED_DOWNLOAD));
		pages["/ulqueue.htm"] = new WebPageInfo(UPLOAD_QUEUE, STRING(SETTINGS_LOG_UPLOADS));
		pages["/ulfinished.htm"] = new WebPageInfo(UPLOAD_FINISHED, STRING(FINISHED_UPLOADS));
		pages["/weblog.htm"] = new WebPageInfo(LOG, STRING(SETTINGS_LOG_WEBSERVER));
		pages["/syslog.htm"] = new WebPageInfo(SYSLOG, STRING(SETTINGS_LOG_SYSTEM_MESSAGES));
		pages["/search.htm"] = new WebPageInfo(SEARCH, STRING(WEBSERVER_SEARCH_PAGE_NAME));
		pages["/settings.htm"] = new WebPageInfo(SETTINGS, STRING(SETTINGS));
		pages["/logs.htm"] = new WebPageInfo(LOGS, STRING(SETTINGS_LOGS));
		pages["/logout.htm"] = new WebPageInfo(LOGOUT, STRING(LOG_OUT));
		
		head =  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
		head += "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n";
		head += "<head>\n";
		head += "<link rel=\"stylesheet\" href=\"webserver.css\" type=\"text/css\" title=\"Default style\" media=\"screen\" />\n";
		head += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n";
		head += "<meta http-equiv=\"pragma\" content=\"no-cache\" />\n";
		head += "<meta http-equiv=\"cache-control\" content=\"no-cache, must-revalidate\" />\n";
	//TODO  head += "<script type=\"text/javascript\" src=\"JS/qTip.js\"></script>\n"; реализовать справку в настройках
	
		foot =  "<div id=footer>\n";
		foot += "2008 - 2011 | ViewlinkDC++ Development Team | <a href='http://www.viewlinkdc.blogspot.ru/'><b>ViewLinkDC++</b></a><br />\n"; // TODO translate: title='<b>ViewLinkDC++</b> | Official Site'
		foot += "<a href='http://code.google.com/p/viewlinkdc/issues/list'>﻿Предложения и ошибки вы можете написать здесь</a>\n";
		foot += "<br />" + STRING(WEBSERVER_GENERATED_IN_MESSAGE) + " ";
		
#ifdef _DEBUG_WEB_SERVER_
		AllocConsole();
		freopen("con:", "w", stdout);
		printf("WebServer debug log:\n");
#endif
	} 
	catch(const SocketException&) {}
}

void WebServerManager::Stop()
{
	if (!started) return;
	Lock l(cs);
	if (!started) return;
	started = false;
	
	SafeDelete(page404);
	
	for (WebPages::iterator p = pages.begin(); p != pages.end(); ++p)
	{
		SafeDelete(p->second);
	}
	
	head = Util::emptyString;
	foot = Util::emptyString;
	search_delay = Util::emptyString;
	
#ifdef _DEBUG_WEB_SERVER_
	FreeConsole();
#endif
	socket.removeListener(this);
	socket.disconnect();
}

void WebServerManager::on(ServerSocketListener::IncomingConnection) noexcept
{
	WebServerSocket *wss = new WebServerSocket();
	wss->accept(&socket);
	wss->start();
}

string WebServerManager::getLoginPage()
{
	string pagehtml = head;
	pagehtml += "<title>" APPNAME " " + STRING(WEBSERVER) + " - " + STRING(WEBSERVER_LOGIN_PAGE_NAME) + "</title>\n";
	pagehtml += "</head>\n";
	pagehtml += "<body>\n";
	pagehtml += "<div id=index_content>\n";
	pagehtml += "<h1>" APPNAME " " + STRING(WEBSERVER) + "</h1>\n";
	pagehtml += "<div id=index_logo></div>\n";
	pagehtml += "<form method=get action='index.htm' enctype='multipart/form-data'>\n";
	pagehtml += "<div id=login>\n";
	pagehtml += "<br />\n";
	pagehtml += "<table>\n";
	pagehtml += "<tr><td>" + STRING(SETTINGS_SOCKS5_USERNAME) + ": </td><td><input type=text name=user size=14 /></td></tr>\n";
	pagehtml += "<tr><td>" + STRING(PASSWORD) + ": </td><td><input type=password name=pass size=14 /></td></tr>\n";
	pagehtml += "</table>\n";
	pagehtml += "<left><input class=button type=submit value='" + STRING(LOG_IN) + "' /></left>\n";
	pagehtml += "</div>\n";
	pagehtml += "</form>\n";
	pagehtml += foot;
	pagehtml += Util::getTimeString() + "</div>\n";
	pagehtml += "</div>\n";
	pagehtml += "</body>\n";
	pagehtml += "</html>\n";
	
	string header = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: " + Util::toString(pagehtml.length()) + "\r\n\r\n";
	
	return header + pagehtml;
}

string WebServerManager::getPage(const string& file, const string& IP, UserStatus CurrentUser)
{
#ifdef _DEBUG_WEB_SERVER_
	printf("requested: '%s'\n", file.c_str());
#endif
	string header = "HTTP/1.0 200 OK\r\n";
	
	WebPageInfo *page = page404;
	WebPages::const_iterator f = pages.find(file);
	if (f != pages.end())
		page = f->second;
		
	string pagehtml = head;
	pagehtml += "<title>" APPNAME " " + STRING(WEBSERVER) + "</title>\n";
	
	if ((page->id == SEARCH) && sended_search)
	{
		pagehtml += "<meta http-equiv=\"Refresh\" content=\"" + search_delay + ";URL=search.htm?stop=true\"/>\n";
	}
	
	pagehtml += "</head>\n";
	pagehtml += "<body>\n";
	pagehtml += "<div class=fly>\n";
	pagehtml += "<h1>" APPNAME " " + STRING(WEBSERVER) + "</h1><br />\n";
	pagehtml += "<div class=menu>\n";
	pagehtml += "<a href='logs.htm'>" + STRING(SETTINGS_LOGS) + "</a>\n";
	pagehtml += "<a href='dlqueue.htm'>" + STRING(DOWNLOAD_QUEUE) + "</a>\n";
	pagehtml += "<a href='search.htm'>" + STRING(WEBSERVER_SEARCH_PAGE_NAME) + "</a>\n";
	pagehtml += "<a href='settings.htm'>" + STRING(SETTINGS) + "</a>\n";
	pagehtml += "<a href='logout.htm'>" + STRING(LOG_OUT) + "</a><br /><br />\n";
	pagehtml += IP + " ";
	if (CurrentUser.ispower())
		pagehtml += STRING(WEBSERVER_FULL_USER);
	else
		pagehtml += STRING(WEBSERVER_USER);
		
	pagehtml += "</div>\n";
	
	if ((page->id == SEARCH))
	{
		pagehtml += "<script type=\"text/javascript\" src=\"JS/search4608.js\"></script>\n";
		if (sended_search)
		{
			pagehtml += "<script type=\"text/javascript\">";
			pagehtml += "/*<![CDATA[*/";
			pagehtml += "var limit=" + search_delay + ";";
			pagehtml += "processTimer();";
			//pagehtml += "GetSearchRezult();"; // TODO
			pagehtml += "/*]]>*/";
			pagehtml += "</script>";
		}
	}
	
	pagehtml += "<div id=right>\n";
	switch (page->id)
	{
		case INDEX:
			pagehtml += "<h1>" + STRING(WELCOME) + "</h1>\n";
			pagehtml += "<div class=cont><br />&nbsp;" + STRING(WELCOME) + " " + STRING(TO) + " " APPNAME " " + STRING(WEBSERVER) + "</div>\n";
			break;
			
		case DOWNLOAD_QUEUE:
			pagehtml += getDLQueue();
			break;
			
		case SEARCH:
			pagehtml += getSearch();
			break;
			
		case LOGS:
			pagehtml += getLogsPage();
			break;
			
		case LOG:
			pagehtml += getLogsPage();
			pagehtml += getWebLogs();
			break;
			
		case SYSLOG:
			pagehtml += getLogsPage();
			pagehtml += getSysLogs();
			break;
			
		case DOWNLOAD_FINISHED:
			pagehtml += getLogsPage();
			pagehtml += getFinished(false);
			break;
			
		case UPLOAD_QUEUE:
			pagehtml += getLogsPage();
			pagehtml += getULQueue();
			break;
			
		case UPLOAD_FINISHED:
			pagehtml += getLogsPage();
			pagehtml += getFinished(true);
			break;
			
		case SETTINGS:
			pagehtml += getSettings();
			break;
			
		case LOGOUT:
		{
			map<string, user_login>::const_iterator i = LoggedIn.find(IP);
			if (i != LoggedIn.end())
				LoggedIn.erase(i);
				
			pagehtml = getLoginPage();
			return pagehtml;
		}
		case PAGE_404:
		default:
			int action = -1; // system  managment
			if (file == "/shutdown.htm") action = 0;
			else if (file == "/reboot.htm") action = 2;
			else if (file == "/suspend.htm") action = 3;
			else if (file == "/logoff.htm") action = 1;
			else if (file == "/switch.htm") action = 5;
			else    // system  managment
			{
				header = NotFoundHeader;
				pagehtml += STRING(WEBSERVER_PAGE_NOT_FOUND);
				break;
			} // system  managment
			if (CurrentUser.ispower() && action >= 0)
			{
				fire(WebServerListener::ShutdownPC(), action);
				pagehtml += "&nbsp;" + STRING(WEBSERVER_REGUEST_SENT_OK);
				//LRESULT MainFrame::OnClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
			}
			else
			{
				pagehtml += "&nbsp;" + STRING(WEBSERVER_ONLY_POWER_USER_MESSAGE);
			}
			break;
			
	}
	pagehtml += "</div>\n";
	
	pagehtml += "<div id='icons'>\n"; // system  managment
	pagehtml += "<a href='switch.htm' id=switch></a>\n";
	pagehtml += "<a href='logoff.htm' id=logoff></a>\n";
	pagehtml += "<a href='suspend.htm' id=suspend></a>\n";
	pagehtml += "<a href='reboot.htm' id=reboot></a>\n";
	pagehtml += "<a href='shutdown.htm' id=shutdown></a>\n";
	pagehtml += "</div>\n"; // system  managment
	
	pagehtml += foot;
	pagehtml += Util::getTimeString() + "</div>\n";
	pagehtml += "</div>\n";
	pagehtml += "</body>\n";
	pagehtml += "</html>\n";
	
	header += "Content-Type: text/html\r\nContent-Length: " + Util::toString(pagehtml.length()) + "\r\n\r\n";
	
#ifdef _DEBUG_WEB_SERVER_
	printf("sending: %s\n", (header + pagehtml).c_str());
#endif
	return header + pagehtml;
}

string WebServerManager::getSettings()
{
	string ret = "<h1>" + STRING(SETTINGS) + "</h1><br />\n";
	
	ret += "<form action='settings.htm'>\n<div class=settings>\n";
	ret += "<h2>" + STRING(SHARED) + "</h2><br />\n";
	ret += "<input type=hidden name=refresh value=1 /><input class=button type=submit value='" + STRING(CMD_SHARE_REFRESH) + "' />";
	ret += "</div></form>\n";
	
	ret += "<form action='settings.htm'>\n<div class=settings>\n";
	ret += "<input type=hidden name=purgetth value=1 /><input class=button type=submit value=\"" + STRING(MENU_REFRESH_FILE_LIST_PURGE) + "\" />";
	ret += "</div></form>\n";
	
	ret += "<form action='settings.htm'>\n<div class=settings>\n";
	
	ret += "<div id=webserver title='" + STRING(WEBSERVER) + "'>\n<h2>" + STRING(WEBSERVER) + "</h2><br />\n<table>\n<tr>\n<td></td>\n</tr>";
	ret += "<tr>\n<td>" + STRING(WEBSERVER_SEARCHSIZE) + ": <input type=text name=webss size=5 value='" + Util::toString(SettingsManager::getInstance()->get(SettingsManager::WEBSERVER_SEARCHSIZE, 0)) + "' /></td>\n</tr>\n";
	ret += "<tr>\n<td>" + STRING(WEBSERVER_SEARCHPAGESIZE) + ": <input type='text' name='websps' size='5' value='" + Util::toString(SettingsManager::getInstance()->get(SettingsManager::WEBSERVER_SEARCHPAGESIZE, 0)) + "' /></td>\n</tr>\n";
	ret += "<tr>\n<td><input type=checkbox name=alch_d_d ";
	if (BOOLSETTING(WEBSERVER_ALLOW_CHANGE_DOWNLOAD_DIR))
		ret += "checked=checked";
	ret += "/> " + STRING(WEBSERVER_ALLOW_CHANGE_DOWNLOAD_DIR) + "(" + STRING(WEBSERVER_ONLY_POWER_USER_MESSAGE) + ")</td>\n</tr>\n";
	ret += "</table>\n<br /></div>\n";
	
	ret += "<div id=speed title='" + STRING(SETCZDC_TRANSFER_LIMITING) + "'>\n<h2>" + STRING(SETCZDC_TRANSFER_LIMITING) + "</h2><br />\n<table>\n<tr>\n<td></td>\n</tr>";
	ret += "<tr>\n<td><input type=checkbox name=speedlimit ";
	if (BOOLSETTING(THROTTLE_ENABLE))
		ret += "checked=checked";
	ret += "/> " + STRING(SETCZDC_ENABLE_LIMITING) + "</td>\n</tr>\n";
	ret += "<tr>\n<td>" + STRING(SETCZDC_DOWNLOAD) + ": <input type=text name=downspeed size=5 value='" + Util::toString(SettingsManager::getInstance()->get(SettingsManager::MAX_DOWNLOAD_SPEED_LIMIT_NORMAL, 0)) + "' /> " + STRING(KBPS) + "\n";
	ret += " " + STRING(SETCZDC_UPLOAD) + ": <input type=text name=upspeed size=5 value='" + Util::toString(SettingsManager::getInstance()->get(SettingsManager::MAX_UPLOAD_SPEED_LIMIT_NORMAL, 0)) + "' /> " + STRING(KBPS) + "</td>\n</tr>\n";
	ret += "<tr>\n<td><input type=checkbox name=speedlimitalt ";
	if (BOOLSETTING(TIME_DEPENDENT_THROTTLE))
		ret += "checked=checked ";
	ret += "/> " + STRING(SETCZDC_ALTERNATE_LIMITING) + "</td>\n</tr>\n";
	ret += "<tr>\n<td>" + STRING(SETCZDC_DOWNLOAD) + ": <input type=text name=downspeedt size=5 value='" + Util::toString(SettingsManager::getInstance()->get(SettingsManager::MAX_DOWNLOAD_SPEED_LIMIT_TIME, 0)) + "' /> " + STRING(KBPS) + "\n";
	ret += " " + STRING(SETCZDC_UPLOAD) + ": <input type=text name=upspeedt size=5 value='" + Util::toString(SettingsManager::getInstance()->get(SettingsManager::MAX_UPLOAD_SPEED_LIMIT_TIME, 0)) + "' /> " + STRING(KBPS) + "</td>\n</tr>\n";
	ret += "<tr><td>" + STRING(SETCZDC_ALTERNATE_LIMITING) + " <input type=text name=altspeedtimestart size=5 value='" + Util::toString(SettingsManager::getInstance()->get(SettingsManager::BANDWIDTH_LIMIT_START, 0)) + "' />\n";
	ret += " " + STRING(SETCZDC_TO) + " <input type=text name=altspeedtimestop size=5 value='" + Util::toString(SettingsManager::getInstance()->get(SettingsManager::BANDWIDTH_LIMIT_END, 0)) + "' /></td>\n</tr>\n";
	ret += "</table>\n<br /></div>\n";
	
	ret += "<h2> </h2><br /><br /><div id=subm><input class=button type=submit value='" + STRING(OK) + "' /> <input class='button' type='reset' value='" + STRING(CANCEL) + "' /></div>";
	ret += "</div></form>\n";
	return ret;
}

string WebServerManager::getLogsPage()
{
	string ret = "<h1>" + STRING(SETTINGS_LOGS) + "</h1>\n";
	ret += "<div class=menu><br />\n";
	ret += "<a href='weblog.htm'>" + STRING(SETTINGS_LOG_WEBSERVER) + "</a>\n";
	ret += "<a href='syslog.htm'>" + STRING(SETTINGS_LOG_SYSTEM_MESSAGES) + "</a>\n";
	ret += "<a href='ulfinished.htm'>" + STRING(FINISHED_UPLOADS) + "</a>\n";
	ret += "<a href='ulqueue.htm'>" + STRING(SETTINGS_LOG_UPLOADS) + "</a>\n";
	ret += "<a href='dlfinished.htm'>" + STRING(FINISHED_DOWNLOADS) + "</a><br /><br />\n";
	ret += "</div>";
	return ret;
}

string WebServerManager::getLogs(bool Enable, const string& LogFile, const string& Caption, const string& MessageNotEnable)
{
	string ret = "<h2>" + Caption + "</h2>\n";
	
	const string path = SETTING(LOG_DIRECTORY) + LogFile;
	const size_t datasize = 32768;
	
	try
	{
		File f(path, File::READ, File::OPEN);
		
		const size_t size = f.getSize();
		
		if (size > datasize)
		{
			f.setPos(size - datasize);
		}
		
		if (Enable)
		{
			StringList lines = StringTokenizer<string>(f.read(datasize), "\r\n").getTokens();
			size_t linesCount = lines.size();
			
			for (size_t i = linesCount > 100 ? linesCount - 100 : linesCount; i < (linesCount - 1); i++)
			{
				ret += "<br />&nbsp;" + lines[i] + "\n";
			}
		}
		else
		{
			ret += "&nbsp;<div class=cont>" + MessageNotEnable + "</div>\n";
		}
		
		f.close();
	}
	catch (FileException & e)
	{
		if (Enable)
		{
			ret += "&nbsp;<div class=cont><strong>" + STRING(ERRORS) + ":</strong> " + e.getError() + "</div>\n";
		}
		else
		{
			ret += "&nbsp;<div class=cont>" + MessageNotEnable + "</div>\n";
		}
	}
	
	string::size_type i = 0;
	while ((i = ret.find('\n', i)) != string::npos)
	{
		ret.replace(i++, 1, "<br />");
	}
	return ret;
}

inline string WebServerManager::getWebLogs()
{
	return getLogs(BOOLSETTING(LOG_WEBSERVER), SETTING(LOG_FILE_WEBSERVER),
	               STRING(SETTINGS_LOG_WEBSERVER), STRING(LOGGING_NOT_ENABLED_WEBSERVER));
}

inline string WebServerManager::getSysLogs()
{
	return getLogs(BOOLSETTING(LOG_WEBSERVER), SETTING(LOG_FILE_SYSTEM),
	               STRING(SETTINGS_LOG_SYSTEM_MESSAGES), STRING(LOGGING_NOT_ENABLED_SYSTEM));
}

string WebServerManager::getSearch()
{
	string ret = "<form name=form_S method=get action='search.htm' enctype='multipart/form-data'>\n";
	ret += "<div class=cont>\n";
	if (sended_search)
	{
		ret += "<br /><br /><strong>" + STRING(SEARCH_FOR) + " " + STRING(PLEASE_WAIT) + "</strong>\n<div class='cont' id='timer'><br /></div>\n";
		ret += "<br /><input class=button type=submit name=stop value='" + STRING(STOP) + "'/>\n";
		sended_search = false;// search_started; TODO
	}
	else
	{
		ret += "<h1>" + STRING(WEBSERVER_SEARCH_PAGE_NAME) + "</h1>\n";
		
		if (SETTING(WEBSERVER_ALLOW_CHANGE_DOWNLOAD_DIR))
		{
			ret += "<h2>" + STRING(ADLS_DESTINATION) + "</h2>\n";
			ret += "<br /><input size=80 type=text name=dir id=directory ";
			ret += "value=\"" + SettingsManager::getInstance()->get(SettingsManager::DOWNLOAD_DIRECTORY, 0) + "\" /><br /><br />\n";
		}
		
		ret += "<h2>" + STRING(WEBSERVER_ADD_MAGNET_LINK) + "</h2>\n";
		ret += "<br /><strong>" + STRING(WEBSERVER_MAGNET_LINK) + " </strong><input size=50 type=text name=link />\n";
		ret += "<input class=button type=submit value='" + STRING(ADD2) + "' /><br /><br />\n";
		
		ret += "<h2>" + STRING(SEARCH) + "</h2>\n";
		ret += "<br /><strong>" + STRING(ENTER_SEARCH_STRING) + ": </strong><input size=40 type=text name=search />\n";
		
		ret += "<select class=sel name=type>\n";
		ret += "<option value=0 selected=selected>" + STRING(ANY) + "</option>\n";
		ret += "<option value=1>" + STRING(AUDIO) + "</option>\n";
		ret += "<option value=2>" + STRING(COMPRESSED) + "</option>\n";
		ret += "<option value=3>" + STRING(DOCUMENT) + "</option>\n";
		ret += "<option value=4>" + STRING(EXECUTABLE) + "</option>\n";
		ret += "<option value=5>" + STRING(PICTURE) + "</option>\n";
		ret += "<option value=6>" + STRING(VIDEO) + "</option>\n";
		ret += "<option value=7>" + STRING(DIRECTORY) + "</option>\n";
		ret += "<option value=8>TTH</option>\n";
		ret += "<option value=9>CD-DVD Image</option>\n";
#ifdef IRAINMAN_SEARCH_SUBTITLES
		ret += "<option value=10>" + STRING(SUBTITLES) + "</option>\n";
		ret += "<option value=11>" + STRING(VIDEO_AND_SUBTITLES) + "</option>\n";
#endif
		ret += "</select>\n";
		
		ret += "<input class=button type=submit value='" + STRING(SEARCH) + "' /><br /><br />\n";
	}
	
	if (PageIndex && (PageIndex <= SearchPageNum()))
	{
	
		if (PageIndex > 1)
		{
			ret += "<form name=navigate action='search.htm' class='cont'>\n<br />\n<br />\n";
			ret += "<input type=hidden name=pagenum value='" + Util::toString(PageIndex - 1) + "'/>";
			ret += "<input class=button type=submit value='" + STRING(BACK) + "' />\n</form>\n";
		}
		else
			ret += "<br />\n";
			
		if ((PageIndex > 0) && (PageIndex < SearchPageNum()))
		{
			ret += "<form name=navigate action='search.htm' class=cont>\n<br />\n";
			ret += "<input type=hidden name=pagenum value='" + Util::toString(PageIndex + 1) + "'/>";
			ret += "<input class=button type=submit value='" + STRING(NEXT) + "' />\n<br />\n</form>\n";
		}
		else
			ret += "<br />\n";
			
		ret += "<table>\n<form name=unknown><tr><td><br /></td></tr></form>\n";
		ret += SearchPage[PageIndex];
		ret += "</table>\n";
		
		if (PageIndex > 1)
		{
			ret += "<form name=navigate action='search.htm' class=cont>\n<br />\n";
			ret += "<input type=hidden name=pagenum value='" + Util::toString(PageIndex - 1) + "'/>";
			ret += "<input class=button type=submit value='" + STRING(BACK) + "' />\n</form>\n";
		}
		else
			ret += "<br />\n";
			
		if ((PageIndex > 0) && (PageIndex < SearchPageNum()))
		{
			ret += "<form name=navigate action='search.htm' class=cont>\n<br />\n";
			ret += "<input type=hidden name=pagenum value='" + Util::toString(PageIndex + 1) + "'/>";
			ret += "<input class=button type=submit value='" + STRING(NEXT) + "' />\n<br />\n<br />\n</form>\n";
		}
		else
			ret += "<br />\n";
	}
	
	ret += "</div>\n";
	ret += "</form>\n";
	
	return ret;
}

string WebServerManager::getFinished(bool uploads)
{
	string ret = "<h2>" + (uploads ? STRING(FINISHED_UPLOADS) : STRING(FINISHED_DOWNLOADS));
	ret += "</h2>\n<table>\n<tr class=headlines>\n";
	ret += "<td>" + STRING(TIME) + "</td>\n<td>" + STRING(FILENAME) + "</td>\n<td>" + STRING(SIZE) + "</td>\n</tr>\n";
	
	const FinishedItemList& fl = FinishedManager::getInstance()->lockList(uploads);
	FinishedItemList::const_iterator i = fl.begin();
	UINT count = 100;
	for (; (i != fl.end()) && count; ++i, count--)
	{
		ret += "<tr>\n";
		ret += "<td>" + Util::formatTime("%Y-%m-%d %H:%M:%S", (*i)->getTime()) + "</td>\n";
		ret += "<td>" + Util::getFileName((*i)->getTarget()) + "</td>\n";
		ret += "<td>" + Util::formatBytes((*i)->getSize()) + "</td>\n";
		ret += "</tr>\n";
	}
	ret += "</table>\n";
	FinishedManager::getInstance()->unlockList();
	
	return ret;
}

string WebServerManager::getDLQueue()
{
	string ret = "<h1>" + STRING(DOWNLOAD_QUEUE) + "</h1>\n";
	
	ret += "<table>\n";
	ret += "<tr class=headlines>\n";
	ret += "<td>" + STRING(FILENAME) + "</td>\n";
	ret += "<td>" + STRING(SIZE) + "</td>\n";
	ret += "<td>" + STRING(DOWNLOADED) + "</td>\n";
	ret += "<td>" + STRING(SPEED) + "</td>\n";
	ret += "<td>" + STRING(SEGMENTS) + "</td>\n";
	ret += "<td>" + STRING(MANAGE) + "</td>\n";
	ret += "</tr>\n";
	
	const string ManagementElements = \
	                                  "<option value='" + STRING(AUTO) +    "'>" + STRING(AUTO) +    "</option>\n" + \
	                                  "<option value='" + STRING(PAUSED) +  "'>" + STRING(PAUSED) +  "</option>\n" + \
	                                  "<option value='" + STRING(LOWEST) +  "'>" + STRING(LOWEST) +  "</option>\n" + \
	                                  "<option value='" + STRING(LOW) +     "'>" + STRING(LOW) +     "</option>\n" + \
	                                  "<option value='" + STRING(NORMAL) +  "'>" + STRING(NORMAL) +  "</option>\n" + \
	                                  "<option value='" + STRING(HIGH) +    "'>" + STRING(HIGH) +    "</option>\n" + \
	                                  "<option value='" + STRING(HIGHEST) + "'>" + STRING(HIGHEST) + "</option>\n" + \
	                                  "</select>\n" + \
	                                  "<input class=button type=submit name=dqueue value='" + STRING(SET_PRIORITY) + "' />\n" + \
	                                  "<input class=button type=submit name=dqueue value='" + STRING(REMOVE2) + "' onclick=\"return confirm('" + STRING(REALLY_REMOVE) + "')\" /></p></form></td>\n" + \
	                                  "</tr>\n";
	                                  
	QueueManager::LockInstance l_fileQueue;
	const QueueItem::StringMap& li = l_fileQueue.get();
	for (QueueItem::StringMap::const_iterator j = li.begin(); j != li.end(); ++j)
	{
		const QueueItem* aQI = j->second;
		const int64_t size = aQI->getSize();
		/*
		aQI->getTarget();
		aQI->getTargetFileName();
		aQI->getTempTarget();
		aQI->setTarget();
		aQI->setTempTarget();
		aQI->setMaxSegments();
		aQI->getMaxSegments();
		*/
		
		// TODO aQI->getChunksVisualisation();
		
		ret += "<tr>\n";
		ret += "<td>" + aQI->getTargetFileName() + "</td>\n";
		
		const int64_t download = aQI->getDownloadedBytes();
		string percent = "0";
		if (size > 0)
		{
			percent = "(" + Util::toString(double(download * 100. / size)) + "%)";
			ret += "<td>" + Util::formatBytes(size) + "</td>\n";
		}
		else if (size < 0)
		{
			if (QueueItem::FLAG_USER_LIST & aQI->getFlags())
			{
				percent = "(" + STRING(FILE_LIST) + ")";
			}
			else
			{
				percent = "(" + STRING(DIRECTORY) + ")";
				ret += "<input type=hidden name=dqueuedir value=1 />\n";
			}
			ret += "<td> - </td>\n";
		}
		
		ret += "<td>" + Util::formatBytes(download) + " " + percent + "</td>\n";
		ret += "<td>" + (aQI->isRunning() ? Util::formatBytes(aQI->getAverageSpeed()) + "/" + STRING(S) : (aQI->isWaiting() ? STRING(WAITING) : "Not runing")) + "</td>\n"; // [!]TODO translate
		ret += "<td>" + Util::toString((int)aQI->countOnlineUsers()) + "/" + Util::toString(aQI->getMaxSegments()) + "</td>\n";
#ifdef _DEBUG_WEB_SERVER_
		ret += "<td><form method=get onsubmit=\"if(confirm('﻿Точно Точно?? CRAZY MS OS ^^')){this.submit}else{return false;}\" action='dlqueue.htm'>";
#else
		ret += "<td><form method=get action='dlqueue.htm'>";
#endif
		ret += "<p>\n<input type=hidden name=qfile value=\"" + aQI->getTarget() + "\" />\n";
		ret += "<select class=sel name=dp>\n";
		string current_prio;
		switch (aQI->getPriority())
		{
			case QueueItem::PAUSED:
				current_prio = STRING(PAUSED);
				break;
			case QueueItem::LOWEST:
				current_prio = STRING(LOWEST);
				break;
			case QueueItem::LOW:
				current_prio = STRING(LOW);
				break;
			case QueueItem::NORMAL:
				current_prio = STRING(NORMAL);
				break;
			case QueueItem::HIGH:
				current_prio = STRING(HIGH);
				break;
			case QueueItem::HIGHEST:
				current_prio = STRING(HIGHEST);
				break;
			default:
				current_prio = STRING(AUTO);
				break;
		}
		ret += "<option value='" + current_prio + "' selected=selected>" + current_prio + "</option>\n";
		ret += ManagementElements;
	}
	ret += "</table>\n";
	
	return ret;
}

string WebServerManager::getULQueue()
{
	string ret = "<h2>" + STRING(SETTINGS_LOG_UPLOADS) + "</h2>\n";
	ret += "<table>\n";
	ret += "<tr class=headlines>\n";
	ret += "<td>" + STRING(USER) + "</td>\n";
	ret += "<td>" + STRING(FILENAME) + "</td>\n";
	ret += "</tr>\n";
	UploadQueueItem::SlotQueue users = UploadManager::getInstance()->getUploadQueue();
	for (UploadQueueItem::SlotQueue::const_iterator ii = users.begin(); ii != users.end(); ++ii)
	{
		for (UploadQueueItem::List::const_iterator i = ii->second.begin(); i != ii->second.end(); ++i)
		{
			ret += "<tr>\n<td>" + ClientManager::getInstance()->getNicks(ii->first.user)[0] + "</td>\n";
			ret += "<td>" + Util::getFileName((*i)->getFile()) + "</td>\n</tr>\n";
		}
	}
	ret += "</table>\n";
	return ret;
}

StringMap WebServerSocket::getArgs(const string& arguments)
{
	StringMap args;
	
	string::size_type i = 0;
	string::size_type j = 0;
	while ((i = arguments.find("=", j)) != string::npos)
	{
		const string key = arguments.substr(j, i - j);
		string value = arguments.substr(i + 1);
		
		j = i + 1;
		if ((i = arguments.find("&", j)) != string::npos)
		{
			value = arguments.substr(j, i - j);
			j = i + 1;
		}
		
		args[key] = value;
	}
	
	return args;
}

inline bool WebServerManager::noPage(const string& for_find)
{
	if (pages.find(for_find) != pages.end() || for_find == "/shutdown.htm" || for_find == "/reboot.htm" || for_find == "/suspend.htm" || for_find == "/logoff.htm" || for_find == "/switch.htm")
	{
#ifdef _DEBUG_WEB_SERVER_
		dcdebug("This web server page not found, get file:%s\n", for_find.c_str());
#endif
		return false;
	}
	
	return true;
}

int WebServerSocket::run()
{
	char buff[8192];
	memzero(buff, sizeof(buff));
	int test = 0;
	while (true)
	{
		test++;
		if (test >= 10000)
			break;
			
		const int size = recv(sock, buff, sizeof(buff), 0);
		
		string header = buff;
		header = header.substr(0, static_cast<size_t>(size));
		
		const string IP = Util::toString(from.sin_addr.S_un.S_un_b.s_b1) + string(".") + Util::toString(from.sin_addr.S_un.S_un_b.s_b2) + string(".") + Util::toString(from.sin_addr.S_un.S_un_b.s_b3) + string(".") + Util::toString(from.sin_addr.S_un.S_un_b.s_b4);
		
		dcdebug("%s\n", header.c_str());
		
		string::size_type start = 0, end = 0;
		
		if (((start = header.find("GET ")) != string::npos) && (end = header.substr(start + 4).find(" ")) != string::npos)
		{
			if (BOOLSETTING(LOG_WEBSERVER)  && (header.find("?user") == string::npos))
			{
				StringMap params;
				const string file = header.substr(start + 4, end);
				params["file"] = file;
				params["ip"] = IP;
				if (file != "/robots.txt")
					LOG(LogManager::WEBSERVER, params);
			}
			
			string headerF = header.substr(start + 5, end - 1);
			const string::size_type endF = header.find("?");
			const string::size_type bs = header.substr(start + 5).find(" ");
			if ((endF != string::npos) && (endF < bs))
			{
				headerF = header.substr(start + 5, endF - 5);
			}
			string toSend;
			if (WebServerManager::getInstance()->noPage("/" + headerF))
			{
#ifdef _DEBUG_WEB_SERVER_
					printf("requested: '%s'\n", headerF.c_str());
#endif
				toSend = getFile(headerF);
				if (toSend == STRING(WEBSERVER_PAGE_NOT_FOUND))
				{
					string l_header = NotFoundHeader;
					l_header += "Content-Type: text/html\r\nContent-Length: " + Util::toString(toSend.length()) + "\r\n\r\n";
					toSend.insert(0, l_header);
				}
#ifdef _DEBUG_WEB_SERVER_
					printf("sending: %s\n", (toSend).c_str());
#endif
				::send(sock, toSend.c_str(), static_cast<int>(toSend.size()), 0);
				break;
			}
			
			header = header.substr(start + 4, end);
#ifdef _DEBUG_WEB_SERVER_
			dcdebug("%s\n", header.c_str());
#endif
			WebServerManager::UserStatus CurrentUser = WebServerManager::getInstance()->GetUserStatus(IP);
			
			if ((start = header.find("?")) != string::npos)
			{
				const string arguments(header.substr(start + 1));
				header = header.substr(0, start);
				StringMap m = getArgs(arguments);
				if (!m["user"].empty())
				{
					if (m["user"] == SETTING(WEBSERVER_USER) && m["pass"] == SETTING(WEBSERVER_PASS))
					{
						WebServerManager::getInstance()->login(IP);
						CurrentUser = WebServerManager::getInstance()->GetUserStatus(IP);
					}
					else if (m["user"] == SETTING(WEBSERVER_POWER_USER) && m["pass"] == SETTING(WEBSERVER_POWER_PASS))
					{
						WebServerManager::getInstance()->login(IP, true);
						CurrentUser = WebServerManager::getInstance()->GetUserStatus(IP);
					}
				}
				
				if (CurrentUser.isloggedin())
				{
					if (!m["search"].empty())
					{
						WebServerManager::getInstance()->search(Util::encodeURI(m["search"], true), Util::toInt(m["type"]));
					} /*else {
                        WebServerManager::getInstance()->searchstarted(m["search_started"].empty()); // TODO
                    }*/
					if (!m["stop"].empty())
					{
						WebServerManager::getInstance()->reset();
					}
					if (!m["pagenum"].empty())
					{
						WebServerManager::getInstance()->ChangePage(Util::toInt(m["pagenum"]));
					}
					
					string dir;
					if (SETTING(WEBSERVER_ALLOW_CHANGE_DOWNLOAD_DIR))
					{
						if (m["dir"] != Util::emptyString)
						{
							dir = Util::encodeURI(m["dir"], true);
						}
					}
					
					if (!m["name"].empty())
					{
						const WebServerManager::searchresult toAdd = WebServerManager::getInstance()->GetSearchResult(Util::toInt(m["number"]));
						switch (Util::toInt(m["type"]))
						{
							case SearchResult::TYPE_DIRECTORY:
								QueueManager::getInstance()->addDirectory(Util::encodeURI(m["file"], true), HintedUser(toAdd.User, toAdd.HubURL), dir);
								break;
							case SearchResult::TYPE_FILE:
								const string name = Util::encodeURI(m["name"], true);
								const bool l_LoadToTarget = !dir.empty();
								const string DownloadName = l_LoadToTarget ? SETTING(DOWNLOAD_DIRECTORY) + name : name;
								QueueManager::getInstance()->add(name, Util::toInt64(m["size"]), TTHValue(m["tth"]), HintedUser(toAdd.User, toAdd.HubURL));
								if (l_LoadToTarget)
								{
									File::ensureDirectory(dir);
									QueueManager::getInstance()->move(DownloadName, dir + name);
								}
								break;
						}
					}
					if (!m["link"].empty())
					{
						string tmpL = Util::encodeURI(m["link"], true);
						if ((start = tmpL.find("?")) != string::npos)
						{
							string arg = tmpL.substr(start + 1);
							tmpL = tmpL.substr(0, start);
							StringMap Link = getArgs(arg);
							if (Link["xt"].length() == 16)
							{
								TTHValue tth = TTHValue(Link["xt"]);

								if (!Link["dn"].empty())
								{
									const string& DownloadName = Link["dn"];
									QueueManager::getInstance()->add(DownloadName, Util::toInt64(Link["xl"]), tth, HintedUser(UserPtr(), Util::emptyString));
									const bool& l_LoadToTarget = !dir.empty();
									if (l_LoadToTarget)
									{
										File::ensureDirectory(dir);
										QueueManager::getInstance()->move(DownloadName, dir + Link["dn"]);
									}
								}
							}
						}
					}
					if (!m["dqueue"].empty())
					{
						const string dqueue = Util::encodeURI(m["dqueue"], true);
						const string qfile = Util::encodeURI(m["qfile"], true);
						if (dqueue == STRING(REMOVE2))
							QueueManager::getInstance()->remove(qfile);
							
						if (dqueue == STRING(SET_PRIORITY))
						{
							const string dp = Util::encodeURI(m["dp"], true);
							if (dp == STRING(AUTO))
								QueueManager::getInstance()->setAutoPriority(qfile, true);
							else if (dp == STRING(PAUSED))
								QueueManager::getInstance()->setPriority(qfile, QueueItem::PAUSED);
							else if (dp == STRING(LOWEST))
								QueueManager::getInstance()->setPriority(qfile, QueueItem::LOWEST);
							else if (dp == STRING(LOW))
								QueueManager::getInstance()->setPriority(qfile, QueueItem::LOW);
							else if (dp == STRING(NORMAL))
								QueueManager::getInstance()->setPriority(qfile, QueueItem::NORMAL);
							else if (dp == STRING(HIGH))
								QueueManager::getInstance()->setPriority(qfile, QueueItem::HIGH);
							else if (dp == STRING(HIGHEST))
								QueueManager::getInstance()->setPriority(qfile, QueueItem::HIGHEST);
						}
					}
					if (!m["refresh"].empty())
					{
						ShareManager::getInstance()->setDirty();
						ShareManager::getInstance()->refresh(true);
					}
					if (!m["purgetth"].empty())
					{
						ShareManager::getInstance()->setDirty();
						ShareManager::getInstance()->setPurgeTTH();
						ShareManager::getInstance()->refresh(true);
						LogManager::getInstance()->message(STRING(PURGE_TTH_DATABASE)); //[!]NightOrion(translate)
					}
					if (!m["webss"].empty() && !m["websps"].empty() &&
					        !m["upspeed"].empty() && !m["downspeed"].empty() &&
					        !m["upspeedt"].empty() && !m["downspeedt"].empty())
					{
						// [!] IRainman SpeedLimiter: to work correctly, you must first set the upload speed, and only then download speed!
						SET_SETTING(MAX_UPLOAD_SPEED_LIMIT_NORMAL, Util::toInt(m["upspeed"]));
						SET_SETTING(MAX_UPLOAD_SPEED_LIMIT_TIME, Util::toInt(m["upspeedt"]));
						SET_SETTING(MAX_DOWNLOAD_SPEED_LIMIT_NORMAL, Util::toInt(m["downspeed"]));
						SET_SETTING(MAX_DOWNLOAD_SPEED_LIMIT_TIME, Util::toInt(m["downspeedt"]));
						SET_SETTING(THROTTLE_ENABLE, !(m["speedlimit"].empty()));
						SET_SETTING(TIME_DEPENDENT_THROTTLE, !(m["speedlimitalt"].empty()));
						
						if (CurrentUser.ispower())
						{
							SET_SETTING(WEBSERVER_ALLOW_CHANGE_DOWNLOAD_DIR, !(m["alch_d_d"].empty()));
						}
						
						const int timestart = Util::toInt(m["altspeedtimestart"]);
						const int timestop = Util::toInt(m["altspeedtimestop"]);
						if ((0 <= timestart && timestop < 24) || (0 <= timestop && timestart < 24))
						{
							SET_SETTING(BANDWIDTH_LIMIT_START, timestart);
							SET_SETTING(BANDWIDTH_LIMIT_END, timestop);
						}
						SET_SETTING(WEBSERVER_SEARCHSIZE, Util::toInt(m["webss"]));
						SET_SETTING(WEBSERVER_SEARCHPAGESIZE, Util::toInt(m["websps"]));
					}
				}
			}
			
			if (CurrentUser.isloggedin())
			{
				toSend = WebServerManager::getInstance()->getPage(header, IP, CurrentUser);
			}
			else
			{
				toSend = WebServerManager::getInstance()->getLoginPage();
			}
			
			::send(sock, toSend.c_str(), static_cast<int>(toSend.size()), 0);
			break;
		}
	}
	::closesocket(sock);
	delete this;// Cleanup the thread object
	return 0;
}

inline void WebServerManager::search(string search_str, int search_type)
{
	if (sended_search == false)
	{
		string::size_type i = 0;
		while ((i = search_str.find('+', i)) != string::npos)
		{
			search_str.replace(i++, 1, " ");
		}
		if ((SearchManager::TypeModes)search_type == SearchManager::TYPE_TTH)
		{
			search_str = "TTH:" + search_str;
		}
		
		{
			ClientManager::LockInstance l_instance;
			const Client::List& clients = l_instance->getClients();
			sClients.clear();
			for (Client::Iter it = clients.begin(); it != clients.end(); ++it)
			{
				const Client* client = it->second;
				if (!client->isConnected())
					continue;
				sClients.push_back(client->getHubUrl());
			}
		}
		
		token = Util::toString(Util::rand());
		
		SearchManager::getInstance()->addListener(this);
		// TODO: Get ADC searchtype extensions if any is selected
		StringList extList;
		const uint64_t l_searchInterval = SearchManager::getInstance()->search(WebServerManager::getInstance()->sClients, search_str, 0, (SearchManager::TypeModes)search_type, SearchManager::SIZE_DONTCARE, token, extList, (void*)this);
		search_delay = Util::toString(l_searchInterval / 1000 + 15);
		results = Util::emptyString;
		SearchPage.clear();
		PageIndex = 0;
		row = 0;
		sended_search = true;
	}
}

void WebServerManager::on(SearchManagerListener::SR, const SearchResultPtr& aResult) noexcept
{
	{
		Lock l(cs);
		if (!aResult->getToken().empty() && token != aResult->getToken())
			return;
			
		if (row < static_cast<size_t>SETTING(WEBSERVER_SEARCHSIZE))
		{
			string Row = Util::toString(row);
			string User = aResult->getUser()->getFirstNick();
//          string User = ClientManager::getInstance()->getNick(aResult->getUser()->getCID());
//          string User = ClientManager::getInstance()->getNicks(HintedUser(aResult->getUser(), aResult->getHubURL()))[0];
			string File = aResult->getFile();
			string FileName = aResult->getFileName();
			results += "<form method=get name='form" + Row + "' action='search.htm'><p>\n";
			results += "<tr class=search onclick='set_download_dir(\"form" + Row + "\")'>\n";
			switch (aResult->getType())
			{
				case SearchResult::TYPE_FILE:
				{
					string TTH = aResult->getTTH().toBase32();
					int64_t Size = aResult->getSize();
#ifdef _DEBUG_WEB_SERVER_
					results += "<td>" + Row + "</td>\n";
#endif
					results += "<td>" + User + "</td>\n<td>" + FileName + "</td>\n<td>" + Util::formatBytes(Size) + "</td>\n<td>" + TTH + "</td>\n";
					results += "<td><a href=\"magnet:?xt=urn:tree:tiger:" + TTH + "&xl" + Util::toString(Size) + "&dn" + FileName + "\" target=\"_blank\">" + STRING(OPEN) + "</a></td>\n</tr>\n";
					results += "<input type=hidden name=size value='" + Util::toString(Size) + "'/>";
					results += "<input type=hidden name=tth value='" + TTH + "'/>";
					break;
				}
				case SearchResult::TYPE_DIRECTORY:
				{
#ifdef _DEBUG_WEB_SERVER_
					results += "<td>" + Row + "</td>\n";
#endif
					results += "<td>" + User + "</td>\n<td>" + FileName + "</td>\n<td>" + STRING(DIRECTORY) + "</td>\n<td>" + File + "</td>\n</tr>\n";
					results += "<input type=hidden name=number value='" + Row + "'/>\n";
					AddSearchResult(row, aResult->getUser(), aResult->getHubURL());
					break;
				}
			}
			results += "<input type=hidden name=dir/>";
			results += "<input type=hidden name=file value='" + File + "'/>";
			results += "<input type=hidden name=name value='" + FileName + "'/>";
			results += "<input type=hidden name=type value='" + Util::toString(aResult->getType()) + "'/>\n";
			results += "<p></form>\n";
			
			PageIndex = 1;
			WebServerManager::AddSearchPage(results, row / SETTING(WEBSERVER_SEARCHPAGESIZE) + 1);
			row++;
			if ((row % SETTING(WEBSERVER_SEARCHPAGESIZE)) == 0)
				results = Util::emptyString;
		}
	}
}

inline string WebServerSocket::getFile(string& Name)
{
	while (true)
	{
		const string::size_type c = Name.find("/");
		if (c == string::npos)
			break;
			
		Name.erase(c, 1);
		Name.insert(c, PATH_SEPARATOR_STR);
	}
	try
	{
		return File(Util::getWebSErverPath() + Name, File::READ, File::OPEN).read();
	}
	catch (...)
	{
		return STRING(WEBSERVER_PAGE_NOT_FOUND);
	}
}